package org.mobile.api.web;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.rubyeye.xmemcached.MemcachedClient;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;

import org.apache.log4j.Logger;
import org.mobile.api.ApiFactory;
import org.mobile.api.ClientSession;
import org.mobile.api.exception.AccessException;
import org.mobile.api.exception.NoLoginApiException;
import org.mobile.api.exception.NoSuchApiException;
import org.mobile.model.util.Constants;
import org.mobile.model.util.Loggers;
import org.mobile.model.util.ReturnMsg;
import org.mobile.model.util.SysUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.ucmed.alias.api.validator.exception.ValidateException;
import com.ucmed.api.filter.exec.ApiExecFilterManager;
import com.ucmed.api.logger.ApiLoggerFactory;

/**
 * @author sbwkl
 */
@Controller
@RequestMapping("/api/exec/")
public class ApiController extends AbsApiController {

    private static final Logger LOG = Logger.getLogger(Loggers.API);

    @Autowired
    private ApiFactory apiFactory;

    @Autowired
    private ApiLoggerFactory apiLoggerFactory;

    @Autowired(required = true)
    private ApiExecFilterManager apiExecFilterManager;

    @Autowired
    private MemcachedClient memcachedClient;
    /**
     * access statistic.
     */
    protected void accessStatistics(HttpServletRequest request,
            JSONObject jsonReq) throws Exception {
        // 添加log记录
    	  String apiName = jsonReq.optString(Constants.API_NAME);
          Integer userId = null;
          String sessionId = jsonReq.optString("session_id");
          if(!SysUtil.isBlank(sessionId)) {
              ClientSession session = (ClientSession) memcachedClient
                      .get(sessionId);
              if(session != null) {
                  userId = session.getUserId();
              }
          }
          apiLoggerFactory.getLogger(apiName).log(
                  userId == null ? null : userId.toString(), jsonReq);
    }

    /**
     * @param request
     *            HttpServletRequest
     * @param response
     *            HttpServletResponse
     * @param map
     *            参数集合
     * @param key
     *            医院标志
     * @return 结果页面
     */
    @RequestMapping(method = RequestMethod.POST, value = "{key}.htm")
    public String absApi(HttpServletRequest request,
            HttpServletResponse response, ModelMap map,
            @PathVariable String key) {
        long begTime = System.currentTimeMillis();
        response.setContentType("application/json; charset=utf-8");
        String reqStr = request.getParameter("requestData");
        reqStr = reqStr.replace("\\", "");
        JSONObject obj = JSONObject.fromObject(reqStr);
        obj.put("api_name", obj.optString("TX"));
        if(!obj.optString("S","").equals("")){
        	obj.put("session_id", obj.optString("S"));
        }
        reqStr = obj.toString();
        getLogger().info(
                "session is " + (request.getSession()).getId()
                        + " &&&&& REQUEST:\n\n" + reqStr + "\n\n");

        JSONObject jsonReq = null;
        JSONObject jsonRes = null;
        try {
        	key = request.getHeader("K");
            accessControl(request.getHeader(Constants.K), key);
            jsonReq = JSONObject.fromObject(reqStr);
            jsonRes = apiExecFilterManager.filter(jsonReq, request,
                    response);
        } catch(AccessException ae) { // access error
            writeError(ae);
            jsonRes = getApiResult(ReturnMsg.VERIFICATION_FAILURE, ae.getMessage(), "", null);
        } catch(NoLoginApiException ve) {
            writeError(ve);
            jsonRes = getApiResult(ReturnMsg.LOGIN_AFTER_ACCESS, ve.getMessage(), "", null);
        } catch(ValidateException ve) {
            writeError(ve);
            jsonRes = getApiResult(ReturnMsg.PARAMETER_ERROR, ve.getMessage(), "", null);
        } catch(NoSuchApiException ne) {
            writeError(ne);
            jsonRes = getApiResult(ReturnMsg.CAN_NO_FIND_API, ne.getMessage(), "", null);
        } catch(JSONException e) {
            writeError(e);
            jsonRes = getApiResult(ReturnMsg.NO_JSON, "invalid json data", "", null);
        } catch(Exception e) {
            writeError(e);
            jsonRes = getApiResult(ReturnMsg.UNKNOWN_ERROR, "server cause an error", "", null);
        } finally {
            // access statistics
            try {
                accessStatistics(request,
                        jsonReq == null ? JSONObject.fromObject(reqStr)
                                : jsonReq);
            } catch(Exception e) {
                getLogger().error("access statistic get error.", e);
            }
        }
        Long costTime = System.currentTimeMillis() - begTime;
        response.addHeader(Constants.T, costTime.toString());
        jsonRes.put("T", costTime);
        map.put("jsonStr", jsonRes.toString());
        getLogger().info(
                "session is " + (request.getSession()).getId()
                        + "&&&&& RESPONSE is success! this cost time is:"
                        + costTime + " ms !\n\nresponse data is: "
                        + jsonRes.toString() + "\n");
        return "api/x";
    }

    /**
     * controll access for appId and passwd.
     * @throws AccessException
     */
    private void accessControl(String appId, String hospitalKey)
            throws AccessException {
        getApiFactory().validAppAccess(appId, hospitalKey, null);
    }

    private void writeError(Exception e) {
        getLogger().error("server got error.", e);
    }

    protected JSONObject getApiResult(int code, String msg, String info,
            JSONObject params) {
        JSONObject res = new JSONObject();
        res.put(Constants.I, info);
        if(params != null) {
            res.putAll(params);
        }
        res.put(Constants.R, code);
        res.put(Constants.M, msg);
        return res;
    }

    @Override
    protected Logger getLogger() {
        return LOG;
    }

    @Override
    protected ApiFactory getApiFactory() {
        return this.apiFactory;
    }

}
